<?php

namespace app\models;

use \yii\base\InvalidArgumentException;
use yii\base\Model;
use yii\base\UnknownMethodException;
use yii\base\UnknownPropertyException;

/**
 * Created by PhpStorm.
 * User: apple
 * Date: 2/27/22
 * Time: 4:44 PM
 */
class BaseModel extends Model {

    /**
     * 属性
     * @var array
     */
    private $_attributes = [];

    /**
     * 魔法变量获取值
     * @param string $name
     * @return array|mixed|null
     * @throws UnknownPropertyException
     */
    public function __get($name)
    {

        if (empty($name)) return $this->_attributes;


        if (isset($this->_attributes[$name]) || array_key_exists($name, $this->_attributes)) {
            return $this->_attributes[$name];
        }

        if ($this->hasAttribute($name)) {
            return null;
        }

        return parent::__get($name);
    }

    /**
     * 魔法变量设置值
     * @param string $name
     * @param mixed $value
     * @throws UnknownPropertyException
     */
    public function __set($name, $value)
    {

        if ($this->hasAttribute($name)) {
            $this->_attributes[$name] = $value;
        } else {
            parent::__set($name, $value);
        }
    }

    /**
     * 魔法变量检查是否为空
     * @param string $name
     * @return bool
     */
    public function __isset($name)
    {
        try {
            return $this->__get($name) !== null;
        } catch (\Exception $e) {
            return false;
        } catch (\Throwable $t) {
            return false;
        }
    }

    /**
     *  返回是否class存在某个属性
     * @param string $name the name of the attribute
     * @return bool whether the model has an attribute with the specified name.
     */
    protected function hasAttribute($name)
    {

        // 存在了
        if (in_array($name, $this->_attributes) || in_array($name, $this->attributes(), true)) {
            return true;
        }

        $nameFormat = '_' . $name;
        if (property_exists($this, $nameFormat)) {
            return true;
        }

        return false;
    }

    /**
     * Returns the list of all attribute names of the model.
     * The default implementation will return all column names of the table associated with this AR class.
     * @return array list of attribute names.
     */
    public function attributes()
    {

        $scenarios = $this->scenarios();
        $scenario = $this->getScenario();

        $attributes = empty($scenarios[$scenario]) ? [] : $scenarios[$scenario];

        return $attributes;
    }

    /**
     * 获取单个属性
     * If this record is the result of a query and the attribute is not loaded,
     * `null` will be returned.
     * @param string $name the attribute name
     * @return mixed the attribute value. `null` if the attribute is not set or does not exist.
     * @see hasAttribute()
     */
    public function getAttribute($name)
    {
        return isset($this->_attributes[$name]) ? $this->_attributes[$name] : null;
    }

    /**
     * 设置单项值
     * @param string $name the attribute name
     * @param mixed $value the attribute value.
     */
    public function setAttribute($name, $value)
    {

        if ($this->hasAttribute($name)) {
            $this->_attributes[$name] = $value;
        } else {
            throw new InvalidArgumentException(get_class($this) . ' has no attribute named "' . $name . '".');
        }
    }

}
